package logic

import (
	"context"
	"encoding/json"
	"fmt"

	"mall/common/globalkey"
	"mall/common/mqueuex"
	"mall/common/utils/pointy"
	"mall/service/mqueue/common/types"
	"mall/service/mqueue/job/internal/svc"
	"mall/service/order/rpc/orderclient"
	"mall/service/product/rpc/productclient"

	"github.com/hibiken/asynq"
	"github.com/zeromicro/go-zero/core/logx"
	// "github.com/pkg/errors"
)

// var ErrCloseOrderFailed = resultx.NewErrCode(resultx.PAYMENT_AUTO_CLOSE_ORDER_FAILED)

// DeferedCloseOrderProcessor implements asynq.Handler interface.
type DeferedCloseOrderProcessor struct {
	svcCtx *svc.ServiceContext
}

func NewDeferedCloseOrderProcessor(svcCtx *svc.ServiceContext) *DeferedCloseOrderProcessor {
	return &DeferedCloseOrderProcessor{
		svcCtx: svcCtx,
	}
}

// deferred close unpaid order : if return err != nil, asynq will retry
func (l *DeferedCloseOrderProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error {
	var p types.DeferedCloseOrderPayload
	if err := json.Unmarshal(t.Payload(), &p); err != nil {
		// return errors.Wrapf(ErrCloseOrderFailed, "DeferedCloseOrderProcessor payload json.Unmarshal fail: err: %+v , payload: %+v", err, t.Payload())
		return fmt.Errorf("DeferedCloseOrderProcessor payload json.Unmarshal fail: %+v : %w", err, asynq.SkipRetry)
	}
	fmt.Println("NewDeferedCloseOrderProcessor  ProcessTask DeferedCloseOrderPayload!!!!!1", p)

	if len(p.OrderSn) == 0 {
		return fmt.Errorf("DeferedCloseOrderProcessor failed to get order due to invalid param: %+v : %w", p, asynq.SkipRetry)
	}

	order, err := l.svcCtx.OrderRpc.GetOrderBySn(ctx, &orderclient.GetOrderBySnReq{
		Sn:      pointy.GetPointer(p.OrderSn),
		WithSku: pointy.GetPointer(uint32(1)),
	})
	if err != nil {
		return fmt.Errorf("DeferedCloseOrderProcessor Failed to get order err: %+v", err)
	}

	if order.Id == nil || order.OrderType == nil || order.TradeState == nil {
		return fmt.Errorf("DeferedCloseOrderProcessor Failed to get valid data of order: %+v", order)
	}

	if *order.TradeState == globalkey.OrderTradeStateNotPay {
		_, err := l.svcCtx.OrderRpc.UpdateTradeState(ctx, &orderclient.UpdateTradeStateReq{
			Id:         order.Id,
			TradeState: pointy.GetPointer(globalkey.OrderTradeStateAutoCancelled),
		})
		if err != nil {
			// return errors.Wrapf(ErrCloseOrderFailed, "DeferedCloseOrderProcessor close order failed err: %+v, sn: %s ", err, p.OrderSn)
			return fmt.Errorf("DeferedCloseOrderProcessor close order failed: %+v", err)
		}
	}

	if len(order.Skus) > 0 && *order.OrderType != globalkey.OrderTypeVirtual && *order.TradeState == globalkey.OrderTradeStateNotPay {
		var stocks []*productclient.ProductVariationStock
		for _, v := range order.Skus {
			if v.SkuId != nil && v.Quantity != nil && *v.SkuId > 0 && *v.Quantity > 0 {
				stocks = append(stocks, &productclient.ProductVariationStock{
					Id:    *v.SkuId,
					Stock: *v.Quantity,
				})
			}
		}
		if len(stocks) > 0 {
			_, err = l.svcCtx.ProductRpc.SubtractStockRevert(ctx, &productclient.CheckAndSubtractStockReq{
				Data: stocks,
			})
			if err != nil {
				return fmt.Errorf("DeferedCloseOrderProcessor revert stock failed: %+v : %w", err, asynq.SkipRetry)
			}
		}
	}

	err = l.unFreezePointCoupon(p.OrderSn)
	if err != nil {
		logx.Errorw("DeferedCloseOrderProcessor unFreezePointCoupon err", logx.Field("detail", err.Error()))
		return err
	}
	return nil
}

func (l *DeferedCloseOrderProcessor) unFreezePointCoupon(orderSn string) error {
	m := mqueuex.DeferedUnFreezePointCouponMessage{
		OrderSn: pointy.GetPointer(orderSn),
	}
	body, err := json.Marshal(m)
	if err != nil {
		fmt.Println("unFreezePointCoupon orderSn", orderSn)
		logx.Errorw("DeferedCloseOrderProcessor unFreezePointCoupon json.Marshal err", logx.Field("detail", err.Error()))
		return err
	}

	return l.svcCtx.KqDeferredUnFreezePointCouponClient.Push(string(body))
}
